package main

import (
    "fmt"
    "math"
)

// --- 方法的定义 ---
// 方法是绑定到特定类型的函数。

type Rectangle struct {
    Width, Height float64
}

type Circle struct {
    Radius float64
}

// Area 方法绑定到 Rectangle 类型
// (r Rectangle) 称为接收者，它指定了该方法属于哪个类型。
// 这是值接收者，它接收的是 Rectangle 的一个副本。
func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

// Perimeter 方法也绑定到 Rectangle 类型
func (r Rectangle) Perimeter() float64 {
    return 2 * (r.Width + r.Height)
}

// Area 方法绑定到 Circle 类型
// 值接收者
func (c Circle) Area() float64 {
    return math.Pi * c.Radius * c.Radius
}

// --- 指针接收者 ---
// 如果方法需要修改接收者的值，或者接收者本身很大，可以使用指针接收者。

type Book struct {
    Title  string
    Author string
    Price  float64
}

// SetPrice 方法需要修改 Book 的 Price 字段，所以使用指针接收者
func (b *Book) SetPrice(newPrice float64) {
    b.Price = newPrice
}

// --- 接口的定义 ---
// 接口是一组方法签名的集合。
// 接口是抽象类型，它不包含实现，只定义行为。
// 任何类型只要实现了接口中的所有方法，就自动实现了该接口。

// Shape 接口定义了所有形状都应该具有的行为
type Shape interface {
    Area() float64
}

// 如果一个类型实现了接口中的所有方法，那么它就隐式地实现了该接口。
// Rectangle 和 Circle 都实现了 Shape 接口，因为它们都有 Area() 方法。

// --- 接口的使用 ---

// PrintArea 函数接受任何实现了 Shape 接口的类型
func PrintArea(s Shape) {
    fmt.Printf("该形状的面积是: %.2f\n", s.Area())
}

// --- 空接口 ---
// 空接口 interface{} 不包含任何方法。
// 因此，任何类型都实现了空接口。
// 空接口可以用来存储任意类型的值，类似于其他语言中的 Object 或 Any。
func printAnything(value interface{}) {
    fmt.Printf("传入的值的类型是: %T, 值是: %v\n", value, value)
}

// --- 类型断言 ---
// 如何从空接口中获取原始类型的值？
// 类型断言提供了访问接口值底层具体值的方式。
func processValue(i interface{}) {
    // i.(string) 是一个类型断言，它检查 i 的底层值是否为 string 类型
    if str, ok := i.(string); ok {
        fmt.Printf("i 是一个字符串: %s\n", str)
    } else if num, ok := i.(int); ok {
        fmt.Printf("i 是一个整数: %d\n", num)
    } else {
        fmt.Printf("i 的类型是 %T，我们无法处理它\n", i)
    }
}


func main() {
    // --- 调用方法 ---
    r := Rectangle{Width: 3, Height: 4}
    fmt.Printf("矩形 (%.1f x %.1f) 的面积是: %.2f\n", r.Width, r.Height, r.Area())
    fmt.Printf("矩形 (%.1f x %.1f) 的周长是: %.2f\n", r.Width, r.Height, r.Perimeter())

    c := Circle{Radius: 5}
    fmt.Printf("圆形 (半径 %.1f) 的面积是: %.2f\n", c.Radius, c.Area())

    // --- 调用指针接收者方法 ---
    book := Book{Title: "Go语言圣经", Author: "Alan A. A. Donovan", Price: 99.0}
    fmt.Printf("《%s》的原始价格是: %.2f\n", book.Title, book.Price)
    book.SetPrice(89.0)
    fmt.Printf("《%s》的新价格是: %.2f\n", book.Title, book.Price)

    // --- 使用接口实现多态 ---
    // 我们可以将 Rectangle 和 Circle 的实例都传递给接受 Shape 接口的函数
    fmt.Println("\n--- 使用接口 ---")
    PrintArea(r)
    PrintArea(c)

    // 我们也可以创建一个 Shape 类型的切片，存放不同的形状
    shapes := []Shape{r, c}
    fmt.Println("\n--- 遍历形状切片 ---")
    for _, shape := range shapes {
        fmt.Printf("形状类型: %T, 面积: %.2f\n", shape, shape.Area())
    }

    // --- 空接口和类型断言 ---
    fmt.Println("\n--- 空接口与类型断言 ---")
    printAnything(42)
    printAnything("Hello, Go")
    printAnything(r)

    processValue("一个字符串")
    processValue(100)
    processValue(3.14)
}